package hy;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@RestController
public class RedisCtrl {
    @Autowired
    StringRedisTemplate tmp;//用于操作redis
    @Autowired
    Redisson rs;//用于管理分布式锁
    ScheduledExecutorService pool= Executors.newScheduledThreadPool(1);

    @RequestMapping("/reduce")
    public String reduceDock(Integer num)throws Exception{
        //设置键值对的key,value是随机值
        RLock lock=rs.getLock("myLock");

        long last;//减库存后的值
        try{
//向redis中写入一键值对用setnx(k,v),如果不存在就添加键值对，存在就直接返回。
//上锁成功：向下走，超时时间30秒，内部启动定时器，在达到超时的1/3,也就是10秒后，会重新把这个锁（键值对）过期时间设置为30秒，为什么要频繁修改过期时间？因为某个服务器加锁后，服务崩溃，则其他线程就要长时间的等待锁自己过期，所以这个时间不益过长，但也不益过短，因为某个线程加锁后，执行过慢，到过期时间了还没执行完，锁就自动释放，所以就设置一较短过期时间，当前线程在没有崩溃时，可自己给自己续命。
//失败，则内部while自旋，直到能成功获得锁
            lock.lock(20,TimeUnit.SECONDS);

            Thread.sleep(1000000);
//            pool.scheduleAtFixedRate(()->{
//                lock.expire(30,TimeUnit.SECONDS);
//            }, 10, 10, TimeUnit.SECONDS);

            //开始减库存
            last=tmp.opsForValue().increment("dockNum",-num);
        }finally {
            lock.unlock();
        }
        return "扣减成功，剩余："+last;
    }//输入：localhost/reduce?num=2   测试
}